_package("alz.core");

_import("alz.core.Plugin");
_import("alz.core.MetaTable");
//_import("alz.util.URLParser");

/**
 * 异步请求引擎
 */
_class("AjaxEngine", Plugin, function(){
	this._init = function(){
		_super._init.call(this);
		this._http = null;      //[TODO]这个对象应该仅供异步请求队列使用
		this._queue = null;     //请求队列
		this._jsc = 0;          //时间戳
		this._timeout = 10000;  //请求超时时间
	};
	this.create = function(name, app){
		_super.create.apply(this, arguments);
		//this._http = this.getXmlHttpObject();
		this._queue = new MetaTable("_tid");
		this._queue.create(null, "req");
		this._jsc = new Date().getTime();
	};
	this.dispose = function(){
		this._queue.dispose();
		this._queue = null;
		this._http = null;
		_super.dispose.apply(this);
	};
	this.getXmlHttpObject = function(){
		var http;
		//typeof XMLHttpRequest == "function" || typeof XMLHttpRequest == "object"
		if(typeof XMLHttpRequest != "undefined"){
			http = new XMLHttpRequest();
		}else if(typeof ActiveXObject === "function"){
			http = new ActiveXObject("Microsoft.XMLHTTP");
		}else{
			runtime.error("[AjaxEngine::getXmlHttpObject]no support xhr");
		}
		this._http = http;
		return http;
	};
	function compare(a, b){
		return a > b ? 1 : (a < b ? -1 : 0)
	}
	/**
	 * 根据请求地址生成本地存储用的key
	 * @param {String} url
	 * @param {Application} app
	 */
	this._parseUrlKey = function(url, app){
		//var parser = new URLParser(url);
		var p = url.indexOf("?") + 1;
		var key = url.substr(p).replace(/=jsonp\d+$/, "=%3F");
		return url.substr(0, p).replace(/^https?:\/\/[^:\/]+(:\d+)?\//, "/") + key.split("&").sort(compare).join("&");
	};
	/**
	 * 使用本地存储模拟网络请求
	 * req格式:{method,url,params,type}
	 * @param {String} mode 请求方式
	 * @param {Application} app 发送请求的应用
	 * @param {Object} req 请求对象
	 */
	this._fromStorage = function(mode, app, req){
		req.setMode("storage");
		if("jsoncallback" in req._data.params){
			req._data.params["jsoncallback"] = "?";
		}
		req.preprocess();
		var key = this._parseUrlKey(req._url, app);
		var data = app._storage.getItem(key);
		if(data === null){
			var k = key.substr(key.indexOf("?") + 1);
			k = k.replace(/&sid=\d+/, "&sid=0")
					.replace(/&taoyunid=\w+/, "&taoyunid=001");
			var app_data = typeof citylife_data != "undefined" ? citylife_data : {};
			data = {"code": 0, "msg": "", "data": k in app_data ? app_data[k] : []};
		}else{
			data = runtime.parseJson(data);
		}
		req.send(data);
	};
	/**
	 * 基于script标签的异步请求
	 * req格式:{method,url,params,type}
	 * @param {String} mode 请求方式
	 * @param {Application} app 发送请求的应用
	 * @param {Object} req 请求对象
	 */
	this._fromScript = function(mode, app, req){
		req.setMode("script");
		/*
		//使用 jquery 实现
		req._data.url += "jsoncallback=?";
		$.getJSON(req._data.url, req._data.params, function(data){
			req.send(data);
		});
		*/
		var jsonp = req._data.params["jsoncallback"];
		req.preprocess();
		var key = this._parseUrlKey(req._url, app);
		var _this = this;
		var head = document.getElementsByTagName("head")[0];
		var obj = req._script = document.createElement("script");
		var old_onerror = window.onerror;
		function onend(json){
			//obj.onload = null;
			obj.onerror = null;
			head.removeChild(obj);
			runtime.stopTimer(req._timer);
			window.onerror = old_onerror;
			window[jsonp] = null;
			try{
				delete window[jsonp];
			}catch(ex){
			}
			if(json.code >= 0){
				if(app._storage){
					app._storage.setItem(key, JSON.stringify(json));
				}
			}
			req.send(json);
		}
		window[jsonp] = function(json){
			onend(json);
		};
		obj.type = "text/javascript";
		obj.charset = "utf-8";
		//obj.onload = function(){};
		//404,500等会触发该错误
		obj.onerror = function(ev){
			onend({
				"code": -1000,
				"msg" : "script invoke error",
				"data": null,
				"ev"  : ev
			});
		};
		req._timer = runtime.startTimer(this._timeout, this, function(){
			onend({
				"code": -1001,
				"msg" : "script invoke timeout",
				"data": null
			});
		});
		window.onerror = function(/*message, url, line*/){
			if(arguments.length == 3 && req._url == arguments[1]){
				onend({
					"code": -1002,
					"msg" : arguments[0],  //脚本语法错误
					"data": null
				});
			}
			return false;  //屏蔽脚本报错
		};
		head.appendChild(obj);
		obj.src = req._url;
	};
	/**
	 * 基于iframe的异步请求
	 * req格式:{method,url,params,type}
	 * @param {String} mode 请求方式
	 * @param {Application} app 发送请求的应用
	 * @param {Object} req 请求对象
	 */
	this._fromIframe = function(mode, app, req){
		req.setMode("iframe");
	};
	/**
	 * 基于XMLHttpRequest的异步请求
	 * req格式:{method,url,params,type}
	 * @param {String} mode 请求方式
	 * @param {Application} app 发送请求的应用
	 * @param {Object} req 请求对象
	 */
	this._fromXHR = function(mode, app, req){  /*, agent, func*/
		req.setMode("xhr");
		req.preprocessSpecial();  //预处理特殊参数
		req.preprocess();
		req.start();
	};
	this.addRequest =
	/**
	 * 添加一个网络请求调用
	 * @param {Object} req 请求数据(格式:{method, url, params, type, agent, func})
	 * @param {Application} app 发送请求的应用
	 * @return {Number} 回调任务id
	 */
	this.append = function(app, req){
		req.init(app);
		if(req.type == "base64"){
			this._fromXHR("xhr", app, req);
		}else{
			if(app.isFirstRun() || runtime._offline){
				this._fromStorage("store", app, req);
			}else if(app._jsonp){
				req._data.params["jsoncallback"] = "jsonp" + this._jsc++;
				this._fromScript("script", app, req);
			}else{
				this._fromXHR("xhr", app, req);
			}
		}
		this._queue.insertRecord(req);
		return req._tid;
	};
	/**
	 * 删除一个请求
	 * @param {Number} 回调任务编号
	 */
	this.remove = function(cbid){
		this._queue.getItem(cbid).dispose();
		this._queue.deleteRecord(cbid);
	};
	/**
	 * 终止一个请求
	 * @param {Number} cbid 请求回调任务编号
	 * @param {Boolean} hold 是否保留请求信息(供重试之用)
	 */
	this.abort = function(cbid, hold){
		this._queue.getItem(cbid).abort(hold);
	};
	/**
	 * 重试某个请求
	 * @param {Number} 请求回调任务编号
	 */
	this.retry = function(cbid){
		this._queue.getItem(cbid).retry();
	};
});